#
# LsL::Auth.pm
#
# Copyright (C) 2004 Paradigm Services, Inc. All Rights Reserved
#
# $Id: Auth.pm 907 2006-05-19 17:39:37Z bill $
#

package LsL::Auth;

use strict;
use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );
use Carp;
use Exporter;
use URI::Escape;

@EXPORT_OK = qw();
@ISA       = qw(Exporter);
@EXPORT    = qw( );
$VERSION   = 0.1;

my $_current_session = undef;

sub get_current_session {
  return $_current_session;
}

sub user_logout {
  my ($session_key) = (@_);

  my $session_data = HTML::Shark::D_Auth::get_session_data(
    {'session_key' => $session_key} );

  # update ip
  #$r->connection->remote_ip();
  #my $req = Apache2::RequestUtil->request();
  #my $con = $req->connection;

  HTML::Shark::D_Auth::session_audit_insert({userid     => $session_data->{userid},
                                     session_ip => $ENV{'REMOTE_ADDR'}, # $con->remote_ip,
                                     event_type => 'LOGOUT'});

  HTML::Shark::D_Auth::session_delete({session_id => $session_key});
}

sub user_login {
  my ($args) = @_;

  $args->{$_} = (defined $args->{$_}?$args->{$_}:'')
    foreach qw(ccode user passwd digest magic);

  $args->{'magic'} ||= '0';

  #my $user_html  = uri_escape($args->{'user'});
  #my $ccode_html = uri_escape($args->{'ccode'});
  my $user_html  = $args->{'user'};
  my $ccode_html = $args->{'ccode'};

  # grab time from oracle
  my $unixtime = HTML::Shark::D_Util::current_unixtime();

  # clear error strings
  LsL::Error::clear_error();
  LsL::Error::clear_user_error();

  # clear current session
  $_current_session = undef;

  # validate
  my $magic_age = $unixtime - $args->{'magic'};
  if ($magic_age > $LsL::MAX_LOGIN_DELAY) {
    LsL::Error::user_error( 'Although your sign in information may be correct, the sign in page has expired. Please try again.' );
    carp( "Stale login time: $args->{'magic'} ($magic_age seconds old)" );
    return undef;
  }
  #if(!$args->{'ccode'} && !$args->{'user'} && !$args->{'passwd'} ) {
  if(!$args->{'user'} && !$args->{'passwd'} ) {
    LsL::Error::user_error( 'Please enter a valid User Name and Password.');
    return undef;
  }
  #if (!$args->{'ccode'}) {
  #  LsL::Error::user_error( 'Please enter a valid Client/LEA Code.' );
  #  return undef;
  #}
  if (!$args->{'user'}) {
    LsL::Error::user_error( 'Please enter a valid User Name.' );
    return undef;
  }
  if (!$args->{'passwd'}) {
    LsL::Error::user_error( qq{Please enter the password for $user_html.} );
    LsL::Error::user_error( qq{If you've lost your password, click <a href="/auth/password.html">here</a>.} );
    return undef;
  }

  # grab ccode/user record from database
  #my $user = HTML::Shark::D_Auth::get_user_by_login({ccode => lc($args->{'ccode'}),
  my $user = HTML::Shark::D_Auth::get_user_by_login_no_ccode({user  => lc($args->{'user'})});

  # grab IP
  #my $req = Apache2::RequestUtil->request();
  #my $con = $req->connection;
  my $ip  = $ENV{'REMOTE_ADDR'}; # $con->remote_ip;

  unless( ref( $user ) eq 'ARRAY' && scalar @{$user} == 1 ) {
    LsL::Error::user_error( "The username and/or password entered is invalid. Please try again." );
    carp("USERNOTFOUND: ccode=($args->{'ccode'}) user=($args->{'user'}) ip=($ip)");
    return undef;
  }

  # generate password digest if not generated client-side
  $args->{'digest'} = LsL::Util::md5_base64(LsL::Util::md5_base64($args->{'passwd'}) . $args->{'magic'}) unless($args->{'digest'});

  # check password
  my $db_digest =
    LsL::Util::md5_base64($user->[0]->{'passwd'} . $args->{'magic'});

  if ($args->{'digest'} ne $db_digest) {
    LsL::Error::user_error( "The username and/or password entered is invalid. Please try again.");
    carp( "INVALIDPASSWD: ccode=($args->{'ccode'}) user=($args->{'user'}) passwd=($args->{'passwd'}) ip=($ip) CLIENT: $args->{'digest'} != DB: $db_digest");
    return undef;
  }

  return $user->[0]->{'userid'};
}

sub new_session {
  my ($args) = @_;

  my $userid      = (defined $args->{'userid'}?$args->{'userid'}:'');
  my $session_key = (defined $args->{'session_key'}?$args->{'session_key'}:'');

  return undef unless( $session_key && $userid );

  HTML::Shark::D_Auth::session_delete({session_id => $session_key});

  HTML::Shark::D_Auth::session_prune({userid => $userid,
                              age    => $LsL::SESSION_EXPIRE});

  my $timeout = HTML::Shark::D_Auth::get_timeout_flag({'userid' => $userid});
  my $god     = HTML::Shark::D_Auth::get_god_flag({'userid' => $userid});
  my $status  = undef;

  HTML::Shark::D_Auth::session_insert({userid     => $userid,
                               session_id => $session_key,
                               time_out   => $timeout,
                               god        => $god,
                              });

  #if ($status eq 'ok') {
    # we are good to go, add an audit record
    #my $req = Apache2::RequestUtil->request();
    #my $con = $req->connection;

    HTML::Shark::D_Auth::session_audit_insert({userid     => $userid,
                                       session_ip => $ENV{'REMOTE_ADDR'}, # $con->remote_ip,
                                       event_type => 'LOGIN'});
    return 1;
  #} else {
  #  carp("new_session failed: $status") if $status ne 'ok';
  #  return 0;
  #}
}

sub gen_key {
  my ($args) = @_;

  $args->{$_} = (defined $args->{$_}?$args->{$_}:'')
    foreach qw(secret userid);

  return undef unless( $args->{'userid'} && $args->{'secret'} );

  my $session_key = Digest::SHA1::sha1_base64( $args->{'userid'},
    $args->{'secret'} ) .  '::' . Digest::SHA1::sha1_base64( time, rand, $$ );

  return $session_key;
}

sub check_key {
  my ($session_string, $secret, $args) = @_;

  $_current_session = undef;

  # clear error strings
  LsL::Error::clear_user_error();

  # we are not logged in just return
  return undef unless $session_string;

  my $session_data = HTML::Shark::D_Auth::get_session_data(
    {'session_key' => $session_string} );

  # we have an old session key hanging around but we
  # are logged out
  return undef unless $session_data->{'session_key'};

  # update ip
  #my $req = Apache2::RequestUtil->request();
  #my $con = $req->connection;
  $session_data->{'session_ip'} = $ENV{'REMOTE_ADDR'}; # $con->remote_ip;

  # check the empid against the one mashed at login
  my ($key_check, $session_key) = split /::/, $session_string;

  # handle the su case
  my $userid = $session_data->{'su_userid'} || $session_data->{'userid'};

  # bail if we cannot resolve back to userid
  if (Digest::SHA1::sha1_base64($userid, $secret) ne $key_check ) {
      HTML::Shark::D_Auth::session_audit_insert({userid        => $userid,
                                         session_ip    => $ENV{'REMOTE_ADDR'}, # $con->remote_ip,
                                         event_type    => 'CROSSCHECK'});

    carp("Cannot cross check userid: $userid, $session_data->{'userid'}");
    return undef;
  }

  # check timeout
  unless ( $session_data->{'time_out'} ) {
    my $age = $session_data->{'age'};

    return undef if $age eq '';

    if ($age > $LsL::TIMEOUT) {
      LsL::Error::user_error("Session timed out.");
      HTML::Shark::D_Auth::session_audit_insert({userid        => $userid,
                                         session_ip    => $ENV{'REMOTE_ADDR'}, # $con->remote_ip,
                                         event_type    => 'TIMEOUT'});

      carp("Session timed out: $userid");
      return undef;
    }
  }

  # switch user functionality
  if ($session_data->{'god'}) {
    $args->{$_} = (defined $args->{$_}?$args->{$_}:'')
      foreach qw(su.exit su.ccode su.username);

    my $su_exit      = $args->{'su.exit'};
    my $su_lea       = $args->{'su.ccode'};
    my $su_lea_empid = $args->{'su.username'};
    if( $session_data->{'su_userid'} && $su_exit ) {
      $session_data->{'userid'} = $session_data->{'su_userid'};
      $session_data->{'su_userid'} = undef;

      HTML::Shark::D_Auth::session_audit_insert(
        {userid        => $session_data->{'userid'},
         session_ip    => $ENV{'REMOTE_ADDR'}, # $con->remote_ip,
         event_type    => 'SUEXIT'});

      carp( "Resetting superuser" );
    } elsif (!$session_data->{'su_userid'} && $su_lea && $su_lea_empid) {
      my $user = HTML::Shark::D_Auth::get_user_by_login(
        {'ccode' => lc($su_lea), 'user'  => lc ($su_lea_empid)});

      carp( "Attempt to switch user for $su_lea:$su_lea_empid" );

      if (ref( $user ) eq 'ARRAY' && scalar @{$user} == 1 ) {
        $session_data->{'su_userid'} = $session_data->{'userid'};
        $session_data->{'userid'} = $user->[0]->{'userid'};

        HTML::Shark::D_Auth::session_audit_insert(
          {userid        => $session_data->{'su_userid'},
           session_ip    => $ENV{'REMOTE_ADDR'}, # $con->remote_ip,
           event_type    => 'SU',
           modify_userid => $session_data->{'userid'}});

        carp( "Engaging superuser for $su_lea:$su_lea_empid" );
      }
    }
  }

  # update session
  #my $status  = undef;
  HTML::Shark::D_Auth::session_update({session_id => $session_string,
                               su_userid  => $session_data->{'su_userid'},
                               userid     => $session_data->{'userid'},
                               session_ip => $session_data->{'session_ip'},
                               });
                               #status     => \$status});

  #if ($status ne 'ok') {
  #  carp("check_key failed: $status");
  #  return undef;
  #}

  # set current session
  $_current_session = $session_data;

  return ($session_data->{'userid'}, $session_data->{'su_userid'}, $session_data->{'entity_id'}, $session_data->{'cis_entity_id'}, $session_data->{'cis_entity_type'});
}
1;
